/*
 * Copyright (C) 2007 Luca Veltri - University of Parma - Italy
 *
 * This file is part of MjSip (http://www.mjsip.org)
 *
 * MjSip is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * MjSip is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MjSip; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Author(s):
 * Luca Veltri (luca.veltri@unipr.it)
 */

package org.zoolu.net;



import java.io.*;
import java.security.KeyStore;
import java.security.Key;
import java.security.KeyFactory;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.net.ssl.SSLSocket;



/** TLS security context.
 */
public class TlsContext
{
    /** Default cert file extensions */
    public static final String[] CERT_EXTENSIONS={ ".crt", ".pem" };

    /** Default password */
    public static final char[] DEFAULT_PASSWORD=("TLS_CONTEXT_PASSWD").toCharArray();

    /** KeyStore */
    KeyStore ks;

    /** Password */
    char[] passwd=DEFAULT_PASSWORD;

    /** Whether all certificates should be considered trusted.
     * By default, trust_all_certificates=false. */
    boolean trust_all_certificates=false;

    /** Counter of trusted certificates. */
    int trust_count=0;



    /** Creates a new TlsContext. */
    public TlsContext() throws java.security.KeyStoreException, java.security.cert.CertificateException, java.security.NoSuchAlgorithmException, IOException
    {  init();
    }


    /** Creates a new TlsContext. */
    public TlsContext(char[] passwd) throws java.security.KeyStoreException, java.security.cert.CertificateException, java.security.NoSuchAlgorithmException, IOException
    {  if (passwd!=null) this.passwd=passwd;
        init();
    }


    /** Inits the TlsContext. */
    private void init() throws java.security.KeyStoreException, java.security.cert.CertificateException, java.security.NoSuchAlgorithmException, IOException
    {  ks=KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(null,null);
    }


    /** Sets key certificate. */
    public void setKeyCert(String key_file, String cert_file) throws java.security.cert.CertificateException, FileNotFoundException, java.security.KeyStoreException, Exception
    {  Key key=TlsTool.importPrivateKeyBASE64(key_file);
        printOut("key loaded: "+key_file);
        Certificate cert=CertificateFactory.getInstance("x509").generateCertificate(new FileInputStream(cert_file));
        printOut("key cert loaded: "+cert_file);
        setKeyCert(key,cert);
    }


    /** Sets key certificate. */
    public void setKeyCert(Key key, Certificate cert) throws java.security.KeyStoreException
    {  String alias="ssl";
        //printOut("DEBUG: key cert alias: "+alias);
        ks.setCertificateEntry(alias,cert);
        Certificate[] chain={ cert };
        ks.setKeyEntry(alias,key,passwd,chain);
    }


    /** Adds a trusted certificate. */
    public void addTrustCert(String cert_file) throws java.security.cert.CertificateException, FileNotFoundException, java.security.KeyStoreException
    {  Certificate cert=CertificateFactory.getInstance("x509").generateCertificate(new FileInputStream(cert_file));
        printOut("trusted cert loaded: "+cert_file);
        addTrustCert(cert);
    }


    /** Adds a trusted certificate. */
    public void addTrustCert(Certificate cert) throws java.security.KeyStoreException
    {  String alias="ssl-trust-"+(trust_count/10)+((trust_count++)%10);
        //printOut("DEBUG: trusted cert alias: "+alias);
        ks.setCertificateEntry(alias,cert);
    }


    /** Adds all trusted certificates from the specified folder. */
    public void addTrustFolder(String cert_folder) throws java.security.cert.CertificateException, FileNotFoundException, java.security.KeyStoreException
    {  File[] file_list=(new File(cert_folder)).listFiles();
        for (int i=0; i<file_list.length; i++)
        {  File file=file_list[i];
            String file_name=file.getName();
            if (file_name.length()>4)
            {  String extension=file_name.substring(file_name.length()-4);
                for (int k=0; k<CERT_EXTENSIONS.length; k++)
                    if (extension.equalsIgnoreCase(CERT_EXTENSIONS[k]))
                    {  Certificate cert=CertificateFactory.getInstance("x509").generateCertificate(new FileInputStream(file));
                        printOut("trusted cert loaded: "+cert_folder+"/"+file_name);
                        addTrustCert(cert);
                        break;
                    }
            }
        }
    }


    /** Sets trust-all mode. */
    public void setTrustAll(boolean trust)
    {  trust_all_certificates=trust;
        printOut("trust all: "+((trust)? "yes" : "no"));

    }


    /** Wheather it's in trust-all mode. */
    public boolean isTrustAll()
    {  return trust_all_certificates;
    }


    /** Gets KeyStore. */
    public KeyStore getKeyStore()
    {  return ks;
    }


    /** Prints out a message. */
    static void printOut(String str)
    {  System.out.println("TlsContext: "+str);
    }

}
